

package com.xgit.iov.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xgit.iov.admin.execl.UserExcel;
import com.xgit.iov.admin.mapper.SysUserMapper;
import com.xgit.iov.admin.service.*;
import com.xgit.iov.common.core.constant.CacheConstants;
import com.xgit.iov.common.core.constant.CommonConstants;
import com.xgit.iov.common.core.entity.*;
import com.xgit.iov.common.core.model.UserInfo;
import com.xgit.iov.common.core.service.impl.SuperServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author lengleng
 * @date 2019/2/1
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends SuperServiceImpl<SysUserMapper, SysUser> implements SysUserService {

	private final static String LOCK_KEY_USERNAME = "username:";
	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
	private final SysMenuService sysMenuService;
	private final SysRoleService sysRoleService;
	private final SysDeptService sysDeptService;
	private final SysUserRoleService sysUserRoleService;

	/**
	 * 保存用户信息
	 *
	 * @param sysUser 对象
	 * @return success/fail
	 */
	@SneakyThrows
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean saveUser(SysUser sysUser) {
		sysUser.setPassword(ENCODER.encode(sysUser.getPassword()));
		baseMapper.insert(sysUser);
		List<SysUserRole> userRoleList = sysUser.getRole()
			.stream().map(roleId -> {
				SysUserRole userRole = new SysUserRole();
				userRole.setUserId(sysUser.getId());
				userRole.setRoleId(roleId);
				return userRole;
			}).collect(Collectors.toList());
		return sysUserRoleService.saveBatch(userRoleList);
	}

	/**
	 * 通过查用户的全部信息
	 *
	 * @param sysUser 用户
	 * @return
	 */
	@Override
	public UserInfo getUserInfo(SysUser sysUser) {
		UserInfo userInfo = new UserInfo();
		userInfo.setSysUser(sysUser);
		//设置角色列表  （ID）
		List<Long> roleIds = sysRoleService.findRolesByUserId(sysUser.getId())
			.stream()
			.map(SysRole::getId)
			.collect(Collectors.toList());
		userInfo.setRoles(ArrayUtil.toArray(roleIds, Long.class));

		//设置权限列表（menu.permission）
		Set<String> permissions = new HashSet<>();
		if (sysUser.isAdmin()){
			List<String> permissionList  = sysMenuService.list(new QueryWrapper<SysMenu>()
				.eq("del_flag","0")
				.eq("type","1")
				.orderByAsc("sort"))
				.stream()
				.filter(sysMenu -> StringUtils.isNotEmpty(sysMenu.getPermission()))
				.map(SysMenu::getPermission)
				.collect(Collectors.toList());
			permissions.addAll(permissionList);
		} else {
			roleIds.forEach(roleId -> {
				List<String> permissionList = sysMenuService.findMenuByRoleId(roleId)
					.stream()
					.filter(sysMenu -> StringUtils.isNotEmpty(sysMenu.getPermission()))
					.map(SysMenu::getPermission)
					.collect(Collectors.toList());
				permissions.addAll(permissionList);
			});
		}

		userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
		return userInfo;
	}

	/**
	 * 分页查询用户信息（含有角色信息）
	 *
	 * @param page    分页对象
	 * @param sysUser 参数列表
	 * @return
	 */
	@Override
	public IPage getUserWithRolePage(Page page, SysUser sysUser) {
		dataRuleFilter(sysUser);
		return baseMapper.getUserVosPage(page, sysUser);
	}

	/**
	 * 通过ID查询用户信息
	 *
	 * @param id 用户ID
	 * @return 用户信息
	 */
	@Override
	public SysUser getUserVoById(Long id) {
		return baseMapper.getUserVoById(id);
	}

	/**
	 * 删除用户
	 *
	 * @param sysUser 用户
	 * @return Boolean
	 */
	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#sysUser.username")
	public Boolean removeUserById(SysUser sysUser) {
		sysUserRoleService.removeRoleByUserId(sysUser.getId());
		this.removeById(sysUser.getId());
		return Boolean.TRUE;
	}

	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#sysUser.username")
	public Boolean updateUserInfo(SysUser sysUser) {
		SysUser exitUser = baseMapper.getUserVoByUsername(sysUser.getUsername());
		SysUser updateUser = new SysUser();

		Assert.notNull(sysUser.getPassword(),"原密码不存在");
		Assert.notNull(sysUser.getNewPassword(),"新密码不存在");
		Assert.state(ENCODER.matches(sysUser.getPassword(), exitUser.getPassword()),"原密码错误，修改失败");
		updateUser.setPassword(ENCODER.encode(sysUser.getNewPassword()));

		updateUser.setPhone(sysUser.getPhone());
		updateUser.setId(exitUser.getId());
		updateUser.setAvatar(sysUser.getAvatar());
		return this.updateById(updateUser);
	}

	@Override
	public boolean resetPassword(Long[] userIds) {
		SysUser user = new SysUser();
		user.setPassword(ENCODER.encode(CommonConstants.DEF_USER_PASSWORD));
		return this.update(user, Wrappers.<SysUser>update().lambda().in(SysUser::getId, userIds));
	}


	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#sysUser.username")
	public Boolean updateUser(SysUser sysUser) {

		if (StrUtil.isNotBlank(sysUser.getPassword())) {
			sysUser.setPassword(ENCODER.encode(sysUser.getPassword()));
		}
		this.updateById(sysUser);

		sysUserRoleService.remove(Wrappers.<SysUserRole>update().lambda()
			.eq(SysUserRole::getUserId, sysUser.getId()));
		sysUser.getRole().forEach(roleId -> {
			SysUserRole userRole = new SysUserRole();
			userRole.setUserId(sysUser.getId());
			userRole.setRoleId(roleId);
			userRole.insert();
		});
		return Boolean.TRUE;
	}

	/**
	 * 查询上级部门的用户信息
	 *
	 * @param username 用户名
	 * @return R
	 */
	@Override
	public List<SysUser> listAncestorUsersByUsername(String username) {
		SysUser sysUser = this.getOne(Wrappers.<SysUser>query().lambda()
			.eq(SysUser::getUsername, username));

		SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());
		if (sysDept == null) {
			return null;
		}

		Long parentId = sysDept.getParentId();
		return this.list(Wrappers.<SysUser>query().lambda()
			.eq(SysUser::getDeptId, parentId));
	}

	@Override
	public String importUsers(List<UserExcel> userExcelList){
		int successNum = 0;
		int failureNum = 0;
		for(UserExcel userExcel : userExcelList){
			SysUser user = new SysUser();
			BeanUtil.copyProperties(userExcel, user);

			SysUser userInfo =  baseMapper.selectOne(
				new QueryWrapper<SysUser>().eq("username", userExcel.getUsername()));
			if (ObjectUtil.isNotEmpty(userInfo)) {
				failureNum++;
				continue;
			}

			if (StrUtil.isNotEmpty(userExcel.getDeptName())){
				SysDept sysDept = sysDeptService.getOne(new QueryWrapper<SysDept>().eq("name",userExcel.getDeptName()));
				user.setDeptId(sysDept.getId());
			} else {
				failureNum++;
				continue;
			}

			List<Long> roleIds = new ArrayList<>();
			if (StrUtil.isNotEmpty(userExcel.getRoleName())){
				String[] roleNames = userExcel.getRoleName().split(",");
				for (String roleName : CollUtil.toList(roleNames)){
					SysRole sysRole = sysRoleService.getOne(new QueryWrapper<SysRole>().eq("role_name",roleName));
					roleIds.add(sysRole.getId());
				}
				user.setRole(roleIds);
			} else {
				failureNum++;
				continue;
			}

			user.setPassword(CommonConstants.DEF_USER_PASSWORD);
			saveUser(user);
			successNum++;
		};
		return "已成功导入"+successNum+"条数据"+",失败"+failureNum+"条数据!";
	}

	@Override
	public List<UserExcel> exportUsers(SysUser sysUser) {
		List<UserExcel> userExcelList = new ArrayList<>();
		IPage list = baseMapper.getUserVosPage(new Page<>(1, -1), sysUser);
		List<SysUser> userList = list.getRecords();
		for (SysUser user : userList) {
			UserExcel userExcel = new UserExcel();
			BeanUtils.copyProperties(user, userExcel);

			userExcel.setRoleName(user.getRoleList().stream()
				.map(SysRole::getRoleName)
				.collect(Collectors.joining(",")));

			userExcelList.add(userExcel);
		}
		return userExcelList;
	}
}
